package com.xuecheng.content.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONUtil;
import com.xuecheng.base.constant.CourseAuditStatusConstant;
import com.xuecheng.base.util.SecurityUtil;
import com.xuecheng.content.exception.*;
import com.xuecheng.content.mapper.*;
import com.xuecheng.content.model.dto.AuditFailDTO;
import com.xuecheng.content.model.dto.AuditSuccessDTO;
import com.xuecheng.content.model.dto.CourseBaseInfoDTO;
import com.xuecheng.content.model.dto.TeachPlanDTO;
import com.xuecheng.content.model.po.*;
import com.xuecheng.content.service.ICourseAuditService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xuecheng.content.service.ICourseBaseService;
import com.xuecheng.content.service.ICourseTeacherService;
import com.xuecheng.content.service.ITeachPlanService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author 勾新杰
 * @since 2025-02-15
 */
@Service
@RequiredArgsConstructor
public class CourseAuditServiceImpl extends ServiceImpl<CourseAuditMapper, CourseAudit> implements ICourseAuditService {

    /**
     * 课程审核mapper
     */
    private final CourseAuditMapper courseAuditMapper;

    /**
     * 课程基本信息mapper
     */
    private final CourseBaseMapper courseBaseMapper;

    /**
     * 课程营销信息mapper
     */
    private final CourseMarketMapper courseMarketMapper;

    /**
     * 课程计划service
     */
    private final ITeachPlanService teachPlanService;

    /**
     * 课程发布预表mapper
     */
    private final CoursePublishPreMapper coursePublishPreMapper;

    /**
     * 课程教师信息mapper
     */
    private final ICourseTeacherService courseTeacherService;

    /**
     * 课程基本信息service
     */
    private final ICourseBaseService courseBaseService;

    /**
     * 审核通过信息
     */
    private static final String AUDIT_SUCCESS_MSG = "审核通过";

    /**
     * 提交审核
     *
     * @param courseId 课程id
     */
    @Override
    @Transactional
    public void commitAudit(Long courseId) {
        // 0. 获取company id
        Long userCompanyId = Long.valueOf(Objects.requireNonNull(SecurityUtil.getUser()).getCompanyId());
        CourseBase courseBase = courseBaseMapper.selectById(courseId);
        if (courseBase == null) CourseNotFoundException.cast();
        // 1. 判断课程审核状态，如果课程处于已提交状态，则不允许提交
        String auditStatus = courseBase.getAuditStatus();
        if (CourseAuditStatusConstant.SUBMITTED.equals(auditStatus))
            CourseIsAuditingException.cast();
        // 2. 判断提交审核的课程是否属于当前机构
        Long companyId = courseBase.getCompanyId();
        if (!companyId.equals(userCompanyId))
            CourseNotBelongException.cast();
        // 3. 填入课程基本信息和部分营销信息到课程发布预表
        CoursePublishPre coursePublishPre = new CoursePublishPre();
        CourseBaseInfoDTO courseBaseInfo = courseBaseService.getCourseBaseInfoById(courseId);
        BeanUtil.copyProperties(courseBaseInfo, coursePublishPre);
        // 4. 填入课程营销信息
        CourseMarket courseMarket = courseMarketMapper.selectById(courseId);
        String market = JSONUtil.toJsonStr(courseMarket);
        coursePublishPre.setMarket(market);
        // 5. 填入课程计划信息，注意要构建树形关系
        List<TeachPlanDTO> teachPlanDTOList = teachPlanService.queryTreeNodes(courseId);
        String teachPlan = JSONUtil.toJsonStr(teachPlanDTOList);
        coursePublishPre.setTeachplan(teachPlan);
        // 6. 填入课程教师信息
        List<CourseTeacher> courseTeacherList = courseTeacherService.lambdaQuery()
                .eq(courseId != null, CourseTeacher::getCourseId, courseId)
                .list();
        if (courseTeacherList.isEmpty()) CourseHaveNoTeacherException.cast();
        String teacher = JSONUtil.toJsonStr(courseTeacherList);
        coursePublishPre.setTeachers(teacher);
        // 7. 设置提交审核的时间
        coursePublishPre.setCreateDate(LocalDateTime.now());
        // 8. 插入或者更新课程发布预表
        CoursePublishPre select = coursePublishPreMapper.selectById(courseId);
        // 8.1 如果该课程以前有提交过审核，则更新
        if (select != null) coursePublishPreMapper.updateById(coursePublishPre);
        // 8.2 如果该课程以前没有提交过审核，则插入
        else coursePublishPreMapper.insert(coursePublishPre);
        // 9. 更新课程基本信息表审核状态为已提交
        courseBaseMapper.updateById(courseBase.setAuditStatus(CourseAuditStatusConstant.SUBMITTED));
    }

    /**
     * 审核通过
     *
     * @param courseId 课程id
     */
    @Override
    @Transactional
    public void success(Long courseId, AuditSuccessDTO auditSuccessDTO) {
        // 0. 检查
        check(courseId);
        // 1. 更新课程发布预表审核时间
        CoursePublishPre coursePublishPre = CoursePublishPre.builder()
                .id(courseId)
                .auditDate(LocalDateTime.now())
                .build();
        coursePublishPreMapper.updateById(coursePublishPre);
        // 2. 准备信息加入课程审核表
        CourseAudit courseAudit = CourseAudit.builder()
                .auditPeople(auditSuccessDTO.getAuditPeople())
                .auditDate(LocalDateTime.now())
                .auditMind(AUDIT_SUCCESS_MSG)
                .auditStatus(CourseAuditStatusConstant.PASSED)
                .courseId(courseId)
                .build();
        courseAuditMapper.insert(courseAudit);
        // 3. 更新课程基本信息表审核状态为已通过
        CourseBase courseBase = CourseBase.builder()
                .id(courseId)
                .auditStatus(CourseAuditStatusConstant.PASSED)
                .build();
        courseBaseMapper.updateById(courseBase);
    }

    /**
     * 审核失败
     *
     * @param courseId     课程id
     * @param auditFailDTO 审核失败信息
     */
    @Override
    @Transactional
    public void fail(Long courseId, AuditFailDTO auditFailDTO) {
        // 0. 检查
        check(courseId);
        // 1. 更新课程发布预表审核时间
        CoursePublishPre coursePublishPre = CoursePublishPre.builder()
                .id(courseId)
                .auditDate(LocalDateTime.now())
                .build();
        coursePublishPreMapper.updateById(coursePublishPre);
        // 2. 准备信息加入课程审核表
        CourseAudit courseAudit = CourseAudit.builder()
                .auditPeople(auditFailDTO.getAuditPeople())
                .auditDate(LocalDateTime.now())
                .auditMind(auditFailDTO.getAuditMind())
                .auditStatus(CourseAuditStatusConstant.UN_PASS)
                .courseId(courseId)
                .build();
        courseAuditMapper.insert(courseAudit);
        // 3. 更新课程基本信息表审核状态为未通过
        CourseBase courseBase = CourseBase.builder()
                .id(courseId)
                .auditStatus(CourseAuditStatusConstant.UN_PASS)
                .build();
        courseBaseMapper.updateById(courseBase);
    }

    /**
     * 检查该课程是否存在于课程审核列表中并且还未审核
     *
     * @param courseId 课程id
     */
    private void check(Long courseId) {
        // 1. 判断该课程是否存在于待审核列表中
        CoursePublishPre select = coursePublishPreMapper.selectById(courseId);
        if (select == null) CoursePublishPreNotFoundException.cast();
        // 2. 判断该课程是否已经提交过审核，当审核状态为未提交时上述情况已经包括了
        CourseBase selectById = courseBaseMapper.selectById(courseId);
        if (!Objects.equals(selectById.getAuditStatus(), CourseAuditStatusConstant.SUBMITTED))
            CourseHasBeenAuditedException.cast();
    }
}
